/*
 * GestorToken.h
 *
 *  Created on: Dec 16, 2013
 *      Author: m
 */

#ifndef GESTORTOKEN_H_
#define GESTORTOKEN_H_

#include "DSMComun.h"
#include "SharedMemory2.h"
#include "MessageQueue.h"
#include "ColaRemotaTransmisor.h"
#include "ColaRemotaReceptor.h"
#include "ColaRemotaReceptorDirecto.h"
#include "CPrinter.h"
#include "StringUtils.h"

using ipc::MessageQueue;
using ipc::CPrinter;
using ipc::SharedMemory2;

#define CHANNEL_BASENAME "anillo"

template<class T>
class GestorToken
{
protected:
    int m_tokenID;
    T m_valorInicial;

public:
    typedef enum { LIDER, NO_LIDER } mode_t;

    GestorToken( int tokenID ) :
        m_tokenID( tokenID )
    {
    }

    virtual ~GestorToken()
    {
    }

    void inicializarToken( T valorInicial )
    {
        m_valorInicial = valorInicial;
    }

    // Nota: que el modo sea un string es un asco, pero lo
    //  hago porque es la manera más rapida de parsear el argumento!
    void run( std::string modo )
    {
        ArchivoIni config( "config.ini" );

        std::string brokerId_str;
        std::string siguienteBrokerId_str;

        brokerId_str = config.getValue( "brokerId" );
        siguienteBrokerId_str = config.getValue( "AnilloSiguiente" );

        // Inicializar los canales de entrada y salida del anillo
        std::string nombreCanalEntradaAnillo = CHANNEL_BASENAME
                + StringUtils::NumberToString<int>( m_tokenID ) + "."
                + brokerId_str;

        std::string nombreCanalSalidaAnillo = CHANNEL_BASENAME
                + StringUtils::NumberToString<int>( m_tokenID ) + "."
                + siguienteBrokerId_str;

        ColaRemotaReceptorDirecto canalEntradaAnillo( nombreCanalEntradaAnillo );
        ColaRemotaTransmisor canalSalidaAnillo;

        TokenDSM token;
        MessageQueue<TokenDSM> colaEntradaToken =
                MessageQueue<TokenDSM>::get( DSM_IPC_BASEFILE, COLA_ENTREGA_TOKEN );
        MessageQueue<TokenDSM> colaSalidaToken =
                MessageQueue<TokenDSM>::get( DSM_IPC_BASEFILE, COLA_LIBERAR_TOKEN );

        CPrinter::setHeader( "dsmGestorToken", m_tokenID );

        CPrinter::printOut( "INICIADO" );

        // Si soy el lider genero el token por primera y unica vez
        if ( modo.compare("lider") == 0 )
        {
            CPrinter::printOut( "CREANDO EL TOKEN %d", m_tokenID );
            token.idDSM = m_tokenID;
            memcpy( token.data, &m_valorInicial, sizeof(T) );

            // Envio el token al gestor de pedidos
            colaEntradaToken.put( m_tokenID, token );

            // Espero el token del gestor de entregas
            token = colaSalidaToken.get( m_tokenID );

            // Devuelvo el token al anillo
            canalSalidaAnillo.enviarMensaje<TokenDSM>( nombreCanalSalidaAnillo, token );
        }
        else
        {
            if ( modo.compare("no-lider") != 0 )
            {
                CPrinter::printOut( "MODO INVALIDO!" );
                exit( 1 );
            }
        }

        // A partir de aca todos los gestores (lider y no lider) funcionan igual
        while ( true )
        {
            // Espero la llegada del token desde el anillo
            token = canalEntradaAnillo.recibirMensaje<TokenDSM>();

            // Envio el token al gestor de pedidos
            colaEntradaToken.put( m_tokenID, token );

            // Espero el token del gestor de entregas
            token = colaSalidaToken.get( m_tokenID );

            // Devuelvo el token al anillo
            canalSalidaAnillo.enviarMensaje<TokenDSM>( nombreCanalSalidaAnillo, token );
        }
    }
};

#endif /* GESTORTOKEN_H_ */
